import time 
import math

brightness = 0.2

# 字符对照表
charMapping = {
    '0': '111101101101111',
    '1': '010110010010111',
    '2': '111001111100111',
    '3': '111001111001111',
    '4': '101101111001001',
    '5': '111100111001111',
    '6': '111100111101111',
    '7': '111001001001001',
    '8': '111101111101111',
    '9': '111101111001111',
    'a': '010101111101101',
    'b': '110101111101110',
    'c': '111101100101111',
    'd': '110101101101110',
    'e': '111100111100111',
    'f': '111100111100100',
    'g': '11111000101110011111',
    'h': '10011001111110011001',
    'i': '111010010010111',
    'j': '111010010010110',
    'k': '10011010110010101001',
    'l': '100100100100111',
    'm': '1000111011101011000110001',
    'n': '1000111001101011001110001',
    'o': '010101101101010',
    'p': '111101111100100',
    'q': '11101010101011100001',
    'r': '111101111110101',
    's': '111100111001111',
    't': '111010010010010',
    'u': '101101101101111',
    'v': '101101101101010',
    'w': '1000110001101011010111011',
    'x': '101101010101101',
    'y': '101101111001111',
    'z': '00001111001001001111',
    '!': '010010010000010',
    ':': '01010',
    '_': '000000000000111',
    '.': '000000000000010',
    '*': '10000111010001000111',
    '%': '101001010100101',
}

# 图案对照表
drawMapping = {
    'cdro': {
        'code': '00011111100011011100011111100001111100000111110000011111100000111111000001111110',
        'raw': '8'
    },
    'cdrc': {
        'code': '00011111000011011110011111111101111111110111111111011111111100111111100001111100',
        'raw': '8'
    },
    'temp-out': {
        'code': '0111001010010100101001010100011000101110',
        'raw': '8'
    },
    'temp-in': {
        'code': '010010010111111',
        'raw': '5'
    },
    'humi': {
        'code': '0010000100011100111011111111111111101110',
        'raw': '8'
    },
    'wifi': {
        'code': '0000000000000011111000001000001000100111001010010001001001001001000000101000000000100000',
        'raw': '8'
    },
    'wifi-waiting': {
        'code': '0000000000000000000000000000000000010101',
        'raw': '8'
    },
    'wifi-connect': {
        'code': '00000000000000000000100000101000100010100000100000000000',
        'raw': '8'
    },
    'wifi-fail': {
        'code': '0000000000100010101000100010101000100000',
        'raw': '8'
    }
}


def hsv2rgb(h, s, v):
    """
    hsv转换为rgb
    :param h: 色调
    :param s: 饱和度
    :param v: 明度
    :return: rgb值
    """
    h = float(h)
    s = float(s)
    v = float(v)
    h60 = h / 60.0
    h60f = math.floor(h60)
    hi = int(h60f) % 6
    f = h60 - h60f
    p = v * (1 - s)
    q = v * (1 - f * s)
    t = v * (1 - (1 - f) * s)
    r, g, b = 0, 0, 0
    if hi == 0: r, g, b = v, t, p
    elif hi == 1: r, g, b = q, v, p
    elif hi == 2: r, g, b = p, v, t
    elif hi == 3: r, g, b = p, q, v
    elif hi == 4: r, g, b = t, p, v
    elif hi == 5: r, g, b = v, p, q
    r, g, b = int(r * 255), int(g * 255), int(b * 255)
    return r, g, b
 

def rgb2hsv(r, g, b):
    """
    rgb转换为hsv
    :param r: 红色通道值
    :param g: 绿色通道值
    :param b: 蓝色通道值
    :return: hsv值
    """
    r, g, b = r/255.0, g/255.0, b/255.0
    mx = max(r, g, b)
    mn = min(r, g, b)
    df = mx-mn
    if mx == mn:
        h = 0
    elif mx == r:
        h = (60 * ((g-b)/df) + 360) % 360
    elif mx == g:
        h = (60 * ((b-r)/df) + 120) % 360
    elif mx == b:
        h = (60 * ((r-g)/df) + 240) % 360
    if mx == 0:
        s = 0
    else:
        s = df/mx
    v = mx
    return h, s, v


def setBrightness(bn):
    '''
    设置亮度值
    :param bn: 亮度值
    :return: None
    '''
    global brightness
    brightness = bn


def colorControl(color):
    '''
    颜色控制，控制颜色的亮度
    :param color: 颜色(r, g, b)
    :return: color: 颜色(r, g, b)
    '''
    r, g, b = color
    if r == 0 and g == 0 and b == 0:
        return [0, 0, 0]
    h, s, v = rgb2hsv(r, g, b)
    # print(v)
    v = brightness
    r, g, b = hsv2rgb(h, s, v)
    return [r, g, b]


def patternMapper(sourceArr, patternMapperList, raw, col, position, color, mode):
    '''
    将图案映射到二维数组中
    :param sourceArr: 原数组
    :param patternMapperList: 字符坐标列表
    :param raw: 字符坐标列表行数
    :param col: 字符坐标列表列数
    :param position: 映射的起始坐标(x, y)
    :param color: 颜色(r, g, b)
    :param mode: 渲染模式，1为将空白部分清空，0为保留
    :return: 映射下个字符的x轴偏移量
    '''
    y, x = position
    if x > 31 or y > 7:
        return 0
    pointer = 0
    # 清空绘画区域
    # cleanArr(sourceArr, raw, col, position)
    for rawIndex in range(0, raw):
        if y + rawIndex > 7:
            break
        for colIndex in range(0, col):
            if x + colIndex > 31 or x + colIndex < 0:
                # pointer += (col - colIndex)
                pointer += 1
                continue
            if patternMapperList[pointer] == '1':
                sourceArr[y + rawIndex][x + colIndex] = colorControl(color)
            else:
                if mode == 1:
                    sourceArr[y + rawIndex][x + colIndex] = [0, 0, 0]
            pointer += 1
    return col + 1


def charMapper(sourceArr, c, position, color):
    '''
    将单个字符映射到二维数组中
    :param sourceArr: 原数组
    :param c: 字符
    :param position: 映射的起始坐标(x, y)
    :param color: 颜色(r, g, b)
    :return: 映射下个字符的x轴偏移量
    '''
    if c == ' ' or charMapping.get(c) == None:
        cleanArr(sourceArr, 5, 2, position)
        return 2
    charMapperList = list(charMapping.get(c))
    raw = 5
    col = int(len(charMapperList) / raw)
    return patternMapper(sourceArr, charMapperList, raw, col, position, color, 1)


def strMapper(sourceArr, showStr, position, color):
    '''
    将输入的字符串映射到二位数组中
    :param sourceArr: 原数组
    :param showStr: 字符串
    :param position: 映射的起始坐标(x, y)
    :param color: 颜色(r, g, b)
    :return: None
    '''
    y, x = position
    charList = list(showStr)
    for c in charList:
        x += charMapper(sourceArr, c, [y, x], color)
        if x > 31:
            break


def displayStr(sourceArr, np, showStr, position, color):
    '''
    在屏幕上显示字符串
    :param sourceArr: 原数组
    :param np: neopixel对象
    :param showStr: 字符串
    :param position: 映射的起始坐标(x, y)
    :param color: 颜色(r, g, b)
    :return: None
    '''
    strMapper(sourceArr, showStr, position, color)
    arrConvert(sourceArr, np)
    np.write()


def scrollStr(sourceArr, np, showStr, color):
    '''
    显示滚动字幕
    :param sourceArr: 原数组
    :param np: neopixel对象
    :param showStr: 显示的字符串
    :param color: 颜色(r, g, b)
    :return: None
    '''
    x, y = 31, 1
    offset = len(showStr)*-5
    print(offset)
    while x > offset:
        strMapper(sourceArr, showStr, [y, x], color)
        arrConvert(sourceArr, np)
        np.write()
        cleanArr(sourceArr, 8, 32, [0, 0])
        x -= 1
        time.sleep(0.01)


def bootAnimation(sourceArr, np):
    '''
    显示开机动画
    :param sourceArr: 原数组
    :param np: neopixel对象
    :return: None
    '''
    # displayStr(sourceArr, np, 'os start', [1, 1], [17, 48, 17])
    displayStr(sourceArr, np, 'loading', [1, 1], colorControl([17, 48, 17]))
    time.sleep(3)
    cleanPattern(sourceArr, np, 'cdr')


def showPattern(sourceArr, np, drawStr, position, color, mode):
    '''
    显示指定图案
    :param sourceArr: 原数组
    :param np: neopixel对象
    :param drawStr: 显示的图案字符串
    :param position: 显示初始位置
    :param color: 颜色(r, g, b)
    :param mode：控制空白部分样式，1为清空，0为不处理
    :return: None
    '''
    if drawStr == ' ' or drawMapping.get(drawStr) == None:
        return 2     
    drawDict = drawMapping.get(drawStr)
    drawMapperList = list(drawDict.get('code'))
    raw = int(drawDict.get('raw'))
    col = int(len(drawMapperList) / raw)
    patternMapper(sourceArr, drawMapperList, raw, col, position, color, mode)
    arrConvert(sourceArr, np)
    np.write()


def showPoint(sourceArr, np, position, color):
    '''
    显示指定点图案
    :param sourceArr: 原数组
    :param np: neopixel对象
    :param position: 显示初始位置
    :param color: 颜色(r, g, b)
    :return: None
    '''
    y, x = position
    if y<0 or y>7 or x<0 or x>31:
        return None
    sourceArr[y][x] = colorControl(color)
    arrConvert(sourceArr, np)
    np.write()


def cleanPattern(sourceArr, np, mode):
    '''
    清空屏幕
    :param sourceArr: 原数组
    :param np: neopixel对象
    :param mode: 清除样式
    :return: None
    '''
    if mode == 'cdr':
        x = -10
        while x < 31:
            showPattern(sourceArr, np, 'cdro', [0, x], [255, 255, 0], 1)
            x += 1
            time.sleep(0.05)
            showPattern(sourceArr, np, 'cdrc', [0, x], [255, 255, 0], 1)
            x += 1
            time.sleep(0.05)
    elif mode == 'other':
        pass
    return None


def cleanScreen(sourceArr, np):
    '''
    清空屏幕
    :param sourceArr: 原数组
    :param np: neopixel对象
    :return: None
    '''
    cleanArr(sourceArr, 8, 32, [0, 0])
    arrConvert(sourceArr, np)
    np.write()


def cleanArr(sourceArr, raw, col, position):
    '''
    清空二维数组
    :param sourceArr: 原数组
    :param raw: 清空行数
    :param col: 清空列数
    :param position: 清空起始坐标
    :return: None
    '''
    y, x = position
    for rawIndex in range(0, raw):
        for colIndex in range(0, col):
            if rawIndex + y > 7 or rawIndex + y < 0 or colIndex + x > 31 or colIndex + x < 0:
                break
            sourceArr[rawIndex + y][colIndex + x] = [0, 0, 0]


def arrConvert(sourceArr, np):
    '''
    将二维数组按照蛇形排列赋值到np对象数组中
    :param sourceArr: 原数组
    :param np: neopixel对象
    :return: None
    '''
    pointer = 0
    maxCol = len(sourceArr[0])
    maxRaw = len(sourceArr)
    for col in range(0, maxCol):
        for raw in range(0, maxRaw):
            if(col % 2 == 0):
                np[pointer] = sourceArr[raw][col]
            else:
                np[pointer] = sourceArr[maxRaw-raw-1][col]
            pointer += 1







